From 910cd648316459f4b75f00548d3fed144a3a18d2 Mon Sep 17 00:00:00 2001 From: Jyrki Gadinger Date: Tue, 8 Apr 2025 13:09:18 +0200 Subject: [PATCH] fix FileSystem::setModTime on x64 Windows with times > 2038 also removes some unused Utility methods Signed-off-by: Jyrki Gadinger --- src/common/utility.h | 3 --- src/common/utility_win.cpp | 17 +------------- src/csync/std/c_time.cpp | 46 ++++++++++++++++++++------------------ src/csync/std/c_time.h | 2 +- src/libsync/filesystem.cpp | 5 +---- 5 files changed, 27 insertions(+), 46 deletions(-) diff --git a/src/common/utility.h b/src/common/utility.h index 167eb6b8e..dccfd044c 100644 --- a/src/common/utility.h +++ b/src/common/utility.h @@ -294,9 +294,6 @@ namespace Utility { OCSYNC_EXPORT bool registryWalkValues(HKEY hRootKey, const QString &subKey, const std::function &callback); OCSYNC_EXPORT QRect getTaskbarDimensions(); - // Possibly refactor to share code with UnixTimevalToFileTime in c_time.c - OCSYNC_EXPORT void UnixTimeToFiletime(time_t t, FILETIME *filetime); - OCSYNC_EXPORT void FiletimeToLargeIntegerFiletime(FILETIME *filetime, LARGE_INTEGER *hundredNSecs); OCSYNC_EXPORT void UnixTimeToLargeIntegerFiletime(time_t t, LARGE_INTEGER *hundredNSecs); OCSYNC_EXPORT QString formatWinError(long error); diff --git a/src/common/utility_win.cpp b/src/common/utility_win.cpp index e2b917028..eb3d57d5b 100644 --- a/src/common/utility_win.cpp +++ b/src/common/utility_win.cpp @@ -483,24 +483,9 @@ DWORD Utility::convertSizeToDWORD(size_t &convertVar) return static_cast(convertVar); } -void Utility::UnixTimeToFiletime(time_t t, FILETIME *filetime) -{ - LONGLONG ll = Int32x32To64(t, 10000000) + 116444736000000000; - filetime->dwLowDateTime = (DWORD) ll; - filetime->dwHighDateTime = ll >>32; -} - -void Utility::FiletimeToLargeIntegerFiletime(FILETIME *filetime, LARGE_INTEGER *hundredNSecs) -{ - hundredNSecs->LowPart = filetime->dwLowDateTime; - hundredNSecs->HighPart = filetime->dwHighDateTime; -} - void Utility::UnixTimeToLargeIntegerFiletime(time_t t, LARGE_INTEGER *hundredNSecs) { - LONGLONG ll = Int32x32To64(t, 10000000) + 116444736000000000; - hundredNSecs->LowPart = (DWORD) ll; - hundredNSecs->HighPart = ll >>32; + hundredNSecs->QuadPart = (t * 10000000LL) + 116444736000000000LL; } bool Utility::canCreateFileInPath(const QString &path) diff --git a/src/csync/std/c_time.cpp b/src/csync/std/c_time.cpp index b51b5a2d1..5281efa9a 100644 --- a/src/csync/std/c_time.cpp +++ b/src/csync/std/c_time.cpp @@ -25,43 +25,45 @@ #include #ifdef HAVE_UTIMES -int c_utimes(const QString &uri, const struct timeval *times) { - int ret = utimes(QFile::encodeName(uri).constData(), times); - return ret; +int c_utimes(const QString &uri, const time_t time) +{ + struct timeval times[2]; + times[0].tv_sec = times[1].tv_sec = time; + times[0].tv_usec = times[1].tv_usec = 0; + return utimes(QFile::encodeName(uri).constData(), times); } + #else // HAVE_UTIMES #ifdef _WIN32 -// implementation for utimes taken from KDE mingw headers +// based on the implementation for utimes from KDE mingw headers #include #include -#define CSYNC_SECONDS_SINCE_1601 11644473600LL -#define CSYNC_USEC_IN_SEC 1000000LL -//after Microsoft KB167296 -static void UnixTimevalToFileTime(struct timeval t, LPFILETIME pft) + +constexpr long long CSYNC_SECONDS_SINCE_1601 = 11644473600LL; +constexpr long long CSYNC_USEC_IN_SEC = 1000000LL; + +// after Microsoft KB167296, except it uses a `time_t` instead of a `struct timeval`. +// +// `struct timeval` is defined in the winsock.h header of all places, and its fields are two `long`s, +// which even on x64 Windows is 4 bytes wide (i.e. int32). `time_t` on the other hand is 8 bytes +// wide (int64) on x64 Windows as well. +static void UnixTimeToFiletime(const time_t time, LPFILETIME pft) { - LONGLONG ll = 0; - ll = Int32x32To64(t.tv_sec, CSYNC_USEC_IN_SEC*10) + t.tv_usec*10 + CSYNC_SECONDS_SINCE_1601*CSYNC_USEC_IN_SEC*10; + LONGLONG ll = time * CSYNC_USEC_IN_SEC * 10 + CSYNC_SECONDS_SINCE_1601 * CSYNC_USEC_IN_SEC * 10; pft->dwLowDateTime = (DWORD)ll; pft->dwHighDateTime = ll >> 32; } -int c_utimes(const QString &uri, const struct timeval *times) { - FILETIME LastAccessTime; - FILETIME LastModificationTime; +int c_utimes(const QString &uri, const time_t time) +{ + FILETIME filetime; HANDLE hFile = nullptr; auto wuri = uri.toStdWString(); - if(times) { - UnixTimevalToFileTime(times[0], &LastAccessTime); - UnixTimevalToFileTime(times[1], &LastModificationTime); - } - else { - GetSystemTimeAsFileTime(&LastAccessTime); - GetSystemTimeAsFileTime(&LastModificationTime); - } + UnixTimeToFiletime(time, &filetime); hFile=CreateFileW(wuri.data(), FILE_WRITE_ATTRIBUTES, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL+FILE_FLAG_BACKUP_SEMANTICS, nullptr); @@ -87,7 +89,7 @@ int c_utimes(const QString &uri, const struct timeval *times) { return -1; } - if(!SetFileTime(hFile, nullptr, &LastAccessTime, &LastModificationTime)) { + if (!SetFileTime(hFile, nullptr, &filetime, &filetime)) { //can this happen? errno=ENOENT; CloseHandle(hFile); diff --git a/src/csync/std/c_time.h b/src/csync/std/c_time.h index 55a6aa6bc..7d3d862a9 100644 --- a/src/csync/std/c_time.h +++ b/src/csync/std/c_time.h @@ -31,7 +31,7 @@ #include #endif -OCSYNC_EXPORT int c_utimes(const QString &uri, const struct timeval *times); +OCSYNC_EXPORT int c_utimes(const QString &uri, time_t time); #endif /* _C_TIME_H */ diff --git a/src/libsync/filesystem.cpp b/src/libsync/filesystem.cpp index 5b719bd8b..59f375ed2 100644 --- a/src/libsync/filesystem.cpp +++ b/src/libsync/filesystem.cpp @@ -196,10 +196,7 @@ time_t FileSystem::getModTime(const QString &filename) bool FileSystem::setModTime(const QString &filename, time_t modTime) { - struct timeval times[2]; - times[0].tv_sec = times[1].tv_sec = modTime; - times[0].tv_usec = times[1].tv_usec = 0; - int rc = c_utimes(filename, times); + int rc = c_utimes(filename, modTime); if (rc != 0) { qCWarning(lcFileSystem) << "Error setting mtime for" << filename << "failed: rc" << rc << ", errno:" << errno; -- 2.30.2